package comparation;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.TreeMap;

import business.algorithm.predictAlgorithm.AutoRegression;
import business.algorithm.predictAlgorithm.AutoRegressionFE;
import business.algorithm.predictAlgorithm.AutoRegressionMA;
import business.algorithm.predictAlgorithm.BarycentricRationalExtrapolation;
import business.algorithm.predictAlgorithm.BarycentricRationalFE;
import business.algorithm.predictAlgorithm.BarycentricRationalMA;
import business.algorithm.predictAlgorithm.LagrangeExtrapolation;
import business.algorithm.predictAlgorithm.LagrangeFE;
import business.algorithm.predictAlgorithm.LagrangeMA;
import dataAccess.databaseManagement.entity.AssetEntity;
import dataAccess.databaseManagement.entity.PriceEntity;
import dataAccess.databaseManagement.manager.AssetManager;
import dataAccess.databaseManagement.manager.PriceManager;

public class Comparation {

	public static HashMap<AssetEntity, ArrayList<PriceEntity>> references;
	public static ArrayList<PriceEntity> priceEntityList;
	public static AssetManager assetManager = new AssetManager();
	public static PriceManager priceManager = new PriceManager();

	
	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		prepareResources();
		AssetEntity vnIndex = assetManager.getAssetBySymbolAndExchange("^VNINDEX", "INDEX");
		
		//
//		File resultFile = new File("matching_result_all.csv");
//		File resultFile = new File("matching2_result_all.csv");
		File resultFile = new File("matching2b_result_all.csv");
//		File resultFile = new File("matching3_result_all.csv");
//		File resultFile = new File("matching4_result_all.csv");
//		File resultFile = new File("autoregression_result_all.csv");
//		File resultFile = new File("arma_result_all.csv");
//		File resultFile = new File("arfe_result_all.csv");
//		File resultFile = new File("barycentric_result_all.csv");
//		File resultFile = new File("baryMA_result_all.csv");
//		File resultFile = new File("baryFE_result_all.csv");
//		File resultFile = new File("Lagrange_result_all.csv");
//		File resultFile = new File("LagrangeMA_result_all.csv");
//		File resultFile = new File("LagrangeFE_result_all.csv");
		
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(printWriterResult);
		
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),Interval(TrainDirection),PriceCoefficent(TrainDirection),NoSample(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),Interval(TrainPrice),PriceCoefficent(TrainPrice),NoSample(TrainPrice),NoUsing(TrainPrice)");
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),IntervalPrice(TrainDirection),IntervalVolume(TrainDirection),PriceCoefficent(TrainDirection),NoSamplePrice(TrainDirection),NoSampleVolume(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),IntervalPrice(TrainPrice),IntervalVolume(TrainPrice),PriceCoefficent(TrainPrice),NoSamplePrice(TrainPrice),NoSampleVolume(TrainPrice),NoUsing(TrainPrice)");
		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),IntervalPrice(TrainDirection),IntervalVolume(TrainDirection),PriceCoefficent(TrainDirection),NoSample(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),IntervalPrice(TrainPrice),IntervalVolume(TrainPrice),PriceCoefficent(TrainPrice),NoSample(TrainPrice),NoUsing(TrainPrice)");
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),Interval(TrainDirection),PriceCoefficent(TrainDirection),MaxDistance(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),Interval(TrainPrice),PriceCoefficent(TrainPrice),MaxDistance(TrainPrice),NoUsing(TrainPrice)");
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),IntervalPrice(TrainDirection),IntervalVolume(TrainDirection),PriceCoefficent(TrainDirection),MaxPriceDistance(TrainDirection),MaxVolumeDistance(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),IntervalPrice(TrainPrice),IntervalVolume(TrainPrice),PriceCoefficent(TrainPrice),MaxPriceDistance(TrainPrice),MaxVolumeDistance(TrainPrice),NoUsing(TrainPrice)");
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),NoTraining(TrainDirection),ARPeriod(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),NoTraining(TrainPrice),ARPeriod(TrainPrice),NoUsing(TrainPrice)");
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),NoTraining(TrainDirection),ARPeriod(TrainDirection),MAPeriod(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),NoTraining(TrainPrice),ARPeriod(TrainPrice),MAPeriod(TrainPrice), NoUsing(TrainPrice)");
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),NoTraining(TrainDirection),ARPeriod(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),NoTraining(TrainPrice),ARPeriod(TrainPrice),NoUsing(TrainPrice)");
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),NoTraining(TrainDirection),OrderD(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),NoTraining(TrainPrice),OrderD(TrainPrice),NoUsing(TrainPrice)");
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),NoTraining(TrainDirection),OrderD(TrainDirection),MAPeriod(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),NoTraining(TrainPrice),OrderD(TrainPrice),MAPeriod(TrainPrice), NoUsing(TrainPrice)");
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),NoTraining(TrainDirection),OrderD(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),NoTraining(TrainPrice),OrderD(TrainPrice),NoUsing(TrainPrice)");
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),NoTraining(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),NoTraining(TrainPrice),NoUsing(TrainPrice)");
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),NoTraining(TrainDirection),MA_Period(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),NoTraining(TrainPrice),MA_Period(TrainPrice),NoUsing(TrainPrice)");
//		bufferedWriterResult.write("QuarterYear,Size,DirectionError(TrainDirection),PriceError(TrainDirection),NoTraining(TrainDirection),NoUsing(TrainDirection),DirectionError(TrainPrice),PriceError(TrainPrice),NoTraining(TrainPrice),NoUsing(TrainPrice)");
	
		bufferedWriterResult.newLine();
		
		//test algorithm
		Calendar calendar = Calendar.getInstance();
		for (int year = 2011; year <= 2012; ++year) {
			for (int month = 0; month <= 9; month += 3) {
				calendar.set(year, month, 01);
				Date startDate = calendar.getTime();

				calendar.set(year, month + 3, 01);
				Date endDate = calendar.getTime();			
				
				int[] indices = chooseRange(startDate, endDate, priceEntityList);
				if (indices[1] == 0) 
					continue;
				
				//matching
//				double[] result = testingMatching(startDate, endDate,priceEntityList, 22);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6] + "," + result[7] + "," + result[8] + "," + result[3] + "," + result[4] + "," + result[9] + "," + result[10] + "," + result[11] + "," + result[12]);

				//matching2
//				double[] result = testingMatching2(startDate, endDate,priceEntityList, 5);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6] + "," + result[7] + "," + result[8] + "," + result[9] + "," + result[10] + "," + result[3] + "," + result[4] + "," + result[11] + "," + result[12] + "," + result[13] + "," + result[14]+ "," + result[15]+ "," + result[16]);				

				//matching2b
				double[] result = testingMatching2b(startDate, endDate,priceEntityList, 22);
				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6] + "," + result[7] + "," + result[8] + "," + result[9] + "," + result[3] + "," + result[4] + "," + result[10] + ","+ result[11] + "," + result[12] + "," + result[13] + "," + result[14]);				
				
				//matching3
//				double[] result = testingMatching3(startDate, endDate,priceEntityList, 5);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6] + "," + result[7] + "," + result[8] + "," + result[3] + "," + result[4] + "," + result[9] + "," + result[10] + "," + result[11] + "," + result[12]);				

				//matching4
//				double[] result = testingMatching2(startDate, endDate,priceEntityList, 25);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6] + "," + result[7] + "," + result[8] + "," + result[9] + "," + result[10] + "," + result[3] + "," + result[4] + "," + result[11] + "," + result[12] + "," + result[13] + "," + result[14]+ "," + result[15]+ "," + result[16]);								

				//autoregression
//				double[] result = testingAutoRegression(startDate, endDate,priceEntityList, 22, vnIndex);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6] + "," + result[7] + "," + result[3] + "," + result[4] + "," + result[8] + "," + result[9] + "," + result[10]);				
				
				//arma
//				double[] result = testingARMA(startDate, endDate,priceEntityList, 22, vnIndex);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6] + "," + result[7] + "," + result[8] + "," + result[3] + "," + result[4] + "," + result[9] + "," + result[10]+ "," + result[11]+ "," + result[12]);

				
				//arfe
//				double[] result = testingARFE(startDate, endDate,priceEntityList, 22, vnIndex);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6] + "," + result[7] + "," + result[3] + "," + result[4] + "," + result[8] + "," + result[9] + "," + result[10]);

				//barycentric
//				double[] result = testingBarycentric(startDate, endDate,priceEntityList, 22, vnIndex);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6] + "," + result[7] + "," + result[3] + "," + result[4] + "," + result[8] + "," + result[9] + "," + result[10]);
				
				//baryMA
//				double[] result = testingBaryMA(startDate, endDate,priceEntityList, 22, vnIndex);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6] + "," + result[7] + "," + result[8] + "," + result[3] + "," + result[4] + "," + result[9] + "," + result[10]+ "," + result[11]+ "," + result[12]);
				
				//baryFE
//				double[] result = testingBaryFE(startDate, endDate,priceEntityList, 22, vnIndex);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6] + "," + result[7] + "," + result[3] + "," + result[4] + "," + result[8] + "," + result[9] + "," + result[10]);
				
				//Lagrange
//				double[] result = testingLagrange(startDate, endDate,priceEntityList, 22, vnIndex);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6]  + "," + result[3] + "," + result[4] + "," + result[7] + "," + result[8]);

				//LagrangeMA
//				double[] result = testingLagrangeMA(startDate, endDate,priceEntityList, 25, vnIndex);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6] + "," + result[7] + "," + result[3] + "," + result[4] + "," + result[8] + "," + result[9]+ "," + result[10]);
				
				//LagrangeFE
//				double[] result = testingLagrangeFE(startDate, endDate,priceEntityList, 25, vnIndex);
//				bufferedWriterResult.write("Q" + (month/3 + 1) + "Y" + year + "," + result[0] + "," + result[1] + "," + result[2] + "," + result[5] + "," + result[6]  + "," + result[3] + "," + result[4] + "," + result[7] + "," + result[8]);
				
				bufferedWriterResult.newLine();
				bufferedWriterResult.flush();
			}
		}
		
		bufferedWriterResult.close();
	}
	
	@SuppressWarnings("unchecked")
	public static void prepareResources() {
		File referencesFile = new File("references.dat");
		
		if (!referencesFile.exists()) {
			String[] referenceSymbols = { "BVH", "DPM", "FPT", "VIC",
					"MSN", "PVF", "STB", "VCB", "VNM", "HAG", "MBB", "CTG" };
			references = new HashMap<AssetEntity, ArrayList<PriceEntity>>();

			for (int i = 0; i < referenceSymbols.length; ++i) {
				AssetEntity asset = assetManager.getAssetBySymbolAndExchange(
						referenceSymbols[i], "HOSE");
				ArrayList<PriceEntity> priceEntities = priceManager
						.getPriceByAssetID(asset.getAssetID());
				references.put(asset, priceEntities);
			}
			
			FileOutputStream fileOutput = null;
			ObjectOutputStream objectOutput = null;
			try {
				fileOutput = new FileOutputStream(referencesFile);
				objectOutput = new ObjectOutputStream(fileOutput);
				objectOutput.writeObject(references);
				objectOutput.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			FileInputStream fileInput = null;
			ObjectInputStream objectInput = null;
			try {
				fileInput = new FileInputStream(referencesFile);
				objectInput = new ObjectInputStream(fileInput);
				references = (HashMap<AssetEntity, ArrayList<PriceEntity>>) objectInput.readObject();
				objectInput.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
			
		}
		
		File priceEntityListFile = new File("VNINDEX.dat");
		
		if (!priceEntityListFile.exists()) {
			// choose testing asset
			AssetEntity assetEntity = assetManager.getAssetBySymbolAndExchange(
					"^VNINDEX", "INDEX");
			priceEntityList = priceManager.getPriceByAssetID(assetEntity.getAssetID());
			
			FileOutputStream fileOutput = null;
			ObjectOutputStream objectOutput = null;
			try {
				fileOutput = new FileOutputStream(priceEntityListFile);
				objectOutput = new ObjectOutputStream(fileOutput);
				objectOutput.writeObject(priceEntityList);
				objectOutput.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			FileInputStream fileInput = null;
			ObjectInputStream objectInput = null;
			try {
				fileInput = new FileInputStream(priceEntityListFile);
				objectInput = new ObjectInputStream(fileInput);
				priceEntityList = (ArrayList<PriceEntity>) objectInput.readObject();
				objectInput.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
			
		}
		
	}
	
	public static double[] testingMatching(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize) throws IOException {
		//references = new HashMap<AssetEntity, ArrayList<PriceEntity>>();
		
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("matching_result_Y" + calendar.get(Calendar.YEAR) + "Q" + (calendar.get(Calendar.MONTH)/3 + 1) + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(printWriterResult);
		bufferedWriterResult.write("Date,Real,PredictTrainDirection,IntervalDirection,PriceCoefficentDirection,NoSampleDirection,PredictTrainMeanSquare,IntervalMeanSquare,PriceCoefficentMeanSquare,NoSampleMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		MatchingAlgorithm matchingAlgorithm = new MatchingAlgorithm();
		matchingAlgorithm.setPriceEntities(priceEntities);
		matchingAlgorithm.setReferences(references);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] intervals = {5, 10, 15, 20};
		double[] priceCoefficents = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0};
		int[] noSamples = {5, 10, 25, 50};
		int[][][] countDirection = new int[intervals.length][priceCoefficents.length][noSamples.length];
		int[][][] countMeanSquare = new int[intervals.length][priceCoefficents.length][noSamples.length];
		double previousPredictDirection = priceEntities.get(m-1).getClose();
		double previousPredictPrice = priceEntities.get(m-1).getClose();
		
		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int intervalDirection = 0, priceCoefficentDirection = 0, noSampleDirection = 0;
			int intervalMeanSquare = 0, priceCoefficentMeanSquare = 0, noSampleMeanSquare = 0;
			
			for (int iInterval = 0; iInterval < intervals.length; ++iInterval) {
				for (int iPriceCoefficent = 0; iPriceCoefficent < priceCoefficents.length; ++iPriceCoefficent) {
					for (int iNoSample = 0; iNoSample < noSamples.length; ++iNoSample) {
						matchingAlgorithm.setInterval(intervals[iInterval]);
						matchingAlgorithm.setPriceCoefficent(priceCoefficents[iPriceCoefficent]);
						matchingAlgorithm.setVolumeCoefficent(1-priceCoefficents[iPriceCoefficent]);
						matchingAlgorithm.setNoSample(noSamples[iNoSample]);
						
						double directionCost = 0, meanSquareCost = 0, previousPredictTraining = priceEntities.get(i-crossValidationSize-1).getClose();
						
						for (int j = i-crossValidationSize; j < i; ++j) {
							double predict = matchingAlgorithm.predict(j);
							if ((predict - previousPredictTraining)*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
								directionCost++;
							}
							previousPredictTraining = predict;
							meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());
						}
						
						if (directionCost < minDirectionCost) {
							minDirectionCost = directionCost;
							intervalDirection = iInterval;
							priceCoefficentDirection = iPriceCoefficent;
							noSampleDirection = iNoSample;
						}
						
						if (meanSquareCost < minMeanSquareCost) {
							minMeanSquareCost = meanSquareCost;
							intervalMeanSquare = iInterval;
							priceCoefficentMeanSquare = iPriceCoefficent;
							noSampleMeanSquare = iNoSample;
						}
					}
				}
			}
			
			countDirection[intervalDirection][priceCoefficentDirection][noSampleDirection]++;
			countMeanSquare[intervalMeanSquare][priceCoefficentMeanSquare][noSampleMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose();
			String parameterOutput = "";
			
			//Direction
			{
				matchingAlgorithm.setInterval(intervals[intervalDirection]);
				matchingAlgorithm.setPriceCoefficent(priceCoefficents[priceCoefficentDirection]);
				matchingAlgorithm.setVolumeCoefficent(1 - priceCoefficents[priceCoefficentDirection]);
				matchingAlgorithm.setNoSample(noSamples[noSampleDirection]);
				
				double predict = matchingAlgorithm.predict(i);
				output += "," + predict + "," + intervals[intervalDirection] + "," + priceCoefficents[priceCoefficentDirection] + "," + noSamples[noSampleDirection];
				for (Double para : matchingAlgorithm.getParameterList()) {
					parameterOutput += "," + para;
				}
				if ((predict - previousPredictDirection)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainDirectionCost++;
				}
				previousPredictDirection = predict;
				testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
			}
			
			//Mean Square
			{
				matchingAlgorithm.setInterval(intervals[intervalMeanSquare]);
				matchingAlgorithm.setPriceCoefficent(priceCoefficents[priceCoefficentMeanSquare]);
				matchingAlgorithm.setVolumeCoefficent(1 - priceCoefficents[priceCoefficentMeanSquare]);
				matchingAlgorithm.setNoSample(noSamples[noSampleMeanSquare]);
				
				double predict = matchingAlgorithm.predict(i);
				output += "," + predict + "," + intervals[intervalMeanSquare] + "," + priceCoefficents[priceCoefficentMeanSquare] + "," + noSamples[noSampleMeanSquare];
				for (Double para : matchingAlgorithm.getParameterList()) {
					parameterOutput += "," + para;
				}
				if ((predict - previousPredictPrice)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainMeanSquareCost++;
				}
				previousPredictPrice = predict;
				testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
			}

			System.out.println(output+parameterOutput);
			bufferedWriterResult.write(output+parameterOutput);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[13];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[8] = 0;
		result[12] = 0;
		for (int i = 0; i < intervals.length; ++i) {
			for (int j = 0; j < priceCoefficents.length; ++j) {
				for (int k = 0; k < noSamples.length; ++k) {
					if (result[8] < countDirection[i][j][k]) {
						result[8] = countDirection[i][j][k];
						result[5] = intervals[i];
						result[6] = priceCoefficents[j];
						result[7] = noSamples[k];
					}
					if (result[12] < countMeanSquare[i][j][k]) {
						result[12] = countMeanSquare[i][j][k];
						result[9] = intervals[i];
						result[10] = priceCoefficents[j];
						result[11] = noSamples[k];						
					}
				}
			}
		}
		
		return result;
	}

	public static double[] testingMatching2(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize) throws IOException {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("matching2_result_Y" + calendar.get(Calendar.YEAR) + "Q" + (calendar.get(Calendar.MONTH)/3 + 1) + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(
				printWriterResult);
		bufferedWriterResult.write("Date,Real,Volume,PredictTrainDirection,IntervalPriceDirection,IntervalVolumeDirection,PriceCoefficentDirection,NoSamplePriceDirection,NoSampleVolumeDirection,PredictTrainMeanSquare,IntervalPriceMeanSquare,IntervalVolumeMeanSquare,PriceCoefficentMeanSquare,NoSamplePriceMeanSquare,NoSampleVolumeMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		MatchingAlgorithm2 matchingAlgorithm2 = new MatchingAlgorithm2();
		matchingAlgorithm2.setPriceEntities(priceEntities);
		matchingAlgorithm2.setReferences(references);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] intervalPrices = {5, 10, 15, 20};
		int[] intervalVolumes = {5, 10, 15, 20};
		double[] priceCoefficents = {0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1};
		int[] noSamplePrices = {5, 10, 25, 50};
		int[] noSampleVolumes = {5, 10, 25, 50};
		int[][][][][] countDirection = new int[intervalPrices.length][intervalVolumes.length][priceCoefficents.length][noSamplePrices.length][noSampleVolumes.length];
		int[][][][][] countMeanSquare = new int[intervalPrices.length][intervalVolumes.length][priceCoefficents.length][noSamplePrices.length][noSampleVolumes.length];
		double previousPredictDirection = priceEntities.get(m-1).getClose();
		double previousPredictPrice = priceEntities.get(m-1).getClose();

		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int intervalPriceDirection = 0, intervalVolumeDirection = 0, priceCoefficentDirection = 0, noSamplePriceDirection = 0, noSampleVolumeDirection = 0;
			int intervalPriceMeanSquare = 0, intervalVolumeMeanSquare = 0, priceCoefficentMeanSquare = 0, noSamplePriceMeanSquare = 0, noSampleVolumeMeanSquare = 0;
			
			for (int iIntervalPrice = 0; iIntervalPrice < intervalPrices.length; ++iIntervalPrice) {
				for (int iIntervalVolume = 0; iIntervalVolume < intervalVolumes.length; ++iIntervalVolume) {
					for (int iPriceCoefficent = 0; iPriceCoefficent < priceCoefficents.length; ++iPriceCoefficent) {
						for (int iNoSamplePrice = 0; iNoSamplePrice < noSamplePrices.length; ++iNoSamplePrice) {
							for (int iNoSampleVolume = 0; iNoSampleVolume < noSampleVolumes.length; ++iNoSampleVolume) {
								matchingAlgorithm2.setIntervalPrice(intervalPrices[iIntervalPrice]);
								matchingAlgorithm2.setIntervalVolume(intervalVolumes[iIntervalVolume]);
								matchingAlgorithm2.setPriceCoefficent(priceCoefficents[iPriceCoefficent]);
								matchingAlgorithm2.setVolumeCoefficent(1-priceCoefficents[iPriceCoefficent]);
								matchingAlgorithm2.setNoSamplePrice(noSamplePrices[iNoSamplePrice]);
								matchingAlgorithm2.setNoSampleVolume(noSampleVolumes[iNoSampleVolume]);
								
								double directionCost = 0, meanSquareCost = 0,previousPredictTraining = priceEntities.get(i-crossValidationSize-1).getClose();
								
								for (int j = i-crossValidationSize; j < i; ++j) {
									double predict = matchingAlgorithm2.predict(j);
									if ((predict - previousPredictTraining)*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
										directionCost++;
									}
									previousPredictTraining = predict;
									meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());	
								}
								
								if (directionCost < minDirectionCost) {
									minDirectionCost = directionCost;
									intervalPriceDirection = iIntervalPrice;
									intervalVolumeDirection = iIntervalVolume;
									priceCoefficentDirection = iPriceCoefficent;
									noSamplePriceDirection = iNoSamplePrice;
									noSampleVolumeDirection = iNoSampleVolume;
								}
								
								if (meanSquareCost < minMeanSquareCost) {
									minMeanSquareCost = meanSquareCost;
									intervalPriceMeanSquare = iIntervalPrice;
									intervalVolumeMeanSquare = iIntervalVolume;
									priceCoefficentMeanSquare = iPriceCoefficent;
									noSamplePriceMeanSquare = iNoSamplePrice;
									noSampleVolumeMeanSquare = iNoSampleVolume;
								}
							}
						}
					}
				}
			}
			
			countDirection[intervalPriceDirection][intervalVolumeDirection][priceCoefficentDirection][noSamplePriceDirection][noSampleVolumeDirection]++;
			countMeanSquare[intervalPriceMeanSquare][intervalVolumeMeanSquare][priceCoefficentMeanSquare][noSamplePriceMeanSquare][noSampleVolumeMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose() + "," + priceEntities.get(i).getVolume();
			String parameterOutput = "";
			
			//Direction
			{
				matchingAlgorithm2.setIntervalPrice(intervalPrices[intervalPriceDirection]);
				matchingAlgorithm2.setIntervalVolume(intervalVolumes[intervalVolumeDirection]);
				matchingAlgorithm2.setPriceCoefficent(priceCoefficents[priceCoefficentDirection]);
				matchingAlgorithm2.setVolumeCoefficent(1 - priceCoefficents[priceCoefficentDirection]);
				matchingAlgorithm2.setNoSamplePrice(noSamplePrices[noSamplePriceDirection]);
				matchingAlgorithm2.setNoSampleVolume(noSampleVolumes[noSampleVolumeDirection]);
				
				double predict = matchingAlgorithm2.predict(i);
				output += "," + predict + "," + intervalPrices[intervalPriceDirection] +"," + intervalVolumes[intervalVolumeDirection] +"," + priceCoefficents[priceCoefficentDirection] +"," + noSamplePrices[noSamplePriceDirection] + "," + noSampleVolumes[noSampleVolumeDirection];
				for (Double para : matchingAlgorithm2.getParameterList()) {
					parameterOutput += "," + para;
				}

				if ((predict - previousPredictDirection)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainDirectionCost++;
				}
				previousPredictDirection = predict;
				testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
			}
			
			//Mean Square
			{
				matchingAlgorithm2.setIntervalPrice(intervalPrices[intervalPriceMeanSquare]);
				matchingAlgorithm2.setIntervalVolume(intervalVolumes[intervalVolumeMeanSquare]);
				matchingAlgorithm2.setPriceCoefficent(priceCoefficents[priceCoefficentMeanSquare]);
				matchingAlgorithm2.setVolumeCoefficent(1 - priceCoefficents[priceCoefficentMeanSquare]);
				matchingAlgorithm2.setNoSamplePrice(noSamplePrices[noSamplePriceMeanSquare]);
				matchingAlgorithm2.setNoSampleVolume(noSampleVolumes[noSampleVolumeMeanSquare]);
				
				double predict = matchingAlgorithm2.predict(i);
				output += "," + predict + "," + intervalPrices[intervalPriceMeanSquare] +"," + intervalVolumes[intervalVolumeMeanSquare] +"," + priceCoefficents[priceCoefficentMeanSquare] +"," + noSamplePrices[noSamplePriceMeanSquare] + "," + noSampleVolumes[noSampleVolumeMeanSquare];
				for (Double para : matchingAlgorithm2.getParameterList()) {
					parameterOutput += "," + para;
				}
				
				if ((predict - previousPredictPrice)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainMeanSquareCost++;
				}
				previousPredictPrice = predict;
				testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
			}

			System.out.println(output + parameterOutput);
			bufferedWriterResult.write(output + parameterOutput);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[17];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[10] = 0;
		result[16] = 0;
		for (int i = 0; i < intervalPrices.length; ++i) {
			for (int ii = 0; ii < intervalVolumes.length; ++ii) {
				for (int j = 0; j < priceCoefficents.length; ++j) {
					for (int k = 0; k < noSamplePrices.length; ++k) {
						for (int l = 0; l < noSampleVolumes.length; ++l) {
							if (result[10] < countDirection[i][ii][j][k][l]) {
								result[10] = countDirection[i][ii][j][k][l];
								result[5] = intervalPrices[i];
								result[6] = intervalVolumes[ii];
								result[7] = priceCoefficents[j];
								result[8] = noSamplePrices[k];
								result[9] = noSampleVolumes[l];
							}
							if (result[16] < countMeanSquare[i][ii][j][k][l]) {
								result[16] = countMeanSquare[i][ii][j][k][l];
								result[11] = intervalPrices[i];
								result[12] = intervalVolumes[ii];
								result[13] = priceCoefficents[j];
								result[14] = noSamplePrices[k];
								result[15] = noSampleVolumes[l];
							}
						}
					}
				}
			}
		}
		
		return result;
	}	

	public static double[] testingMatching2b(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize) throws IOException {
		//references = new HashMap<AssetEntity, ArrayList<PriceEntity>>();
		
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("matching2b_result_Y" + calendar.get(Calendar.YEAR) + "Q" + (calendar.get(Calendar.MONTH)/3 + 1) + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(
				printWriterResult);
		bufferedWriterResult.write("Date,Real,Volume,PredictTrainDirection,IntervalPriceDirection,IntervalVolumeDirection,PriceCoefficentDirection,NoSampleDirection,PredictTrainMeanSquare,IntervalPriceMeanSquare,IntervalVolumeMeanSquare,PriceCoefficentMeanSquare,NoSampleMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		MatchingAlgorithm2b matchingAlgorithm2 = new MatchingAlgorithm2b();
		matchingAlgorithm2.setPriceEntities(priceEntities);
		matchingAlgorithm2.setReferences(references);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] intervalPrices = {5, 10, 15, 20};
		int[] intervalVolumes = {5, 10, 15, 20};
		double[] priceCoefficents = {0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1};
		int[] noSamples = {5, 10, 25, 50};
		int[][][][] countDirection = new int[intervalPrices.length][intervalVolumes.length][priceCoefficents.length][noSamples.length];
		int[][][][] countMeanSquare = new int[intervalPrices.length][intervalVolumes.length][priceCoefficents.length][noSamples.length];
		double previousPredictDirection = priceEntities.get(m-1).getClose();
		double previousPredictPrice = priceEntities.get(m-1).getClose();

		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int intervalPriceDirection = 0, intervalVolumeDirection = 0, priceCoefficentDirection = 0, noSampleDirection = 0;
			int intervalPriceMeanSquare = 0, intervalVolumeMeanSquare = 0, priceCoefficentMeanSquare = 0, noSampleMeanSquare = 0;
			
			for (int iIntervalPrice = 0; iIntervalPrice < intervalPrices.length; ++iIntervalPrice) {
				for (int iIntervalVolume = 0; iIntervalVolume < intervalVolumes.length; ++iIntervalVolume) {
					for (int iPriceCoefficent = 0; iPriceCoefficent < priceCoefficents.length; ++iPriceCoefficent) {
						for (int iNoSample = 0; iNoSample < noSamples.length; ++iNoSample) {
								matchingAlgorithm2.setIntervalPrice(intervalPrices[iIntervalPrice]);
								matchingAlgorithm2.setIntervalVolume(intervalVolumes[iIntervalVolume]);
								matchingAlgorithm2.setPriceCoefficent(priceCoefficents[iPriceCoefficent]);
								matchingAlgorithm2.setVolumeCoefficent(1-priceCoefficents[iPriceCoefficent]);
								matchingAlgorithm2.setNoSample(noSamples[iNoSample]);
								
								double directionCost = 0, meanSquareCost = 0,previousPredictTraining = priceEntities.get(i-crossValidationSize-1).getClose();
								
								for (int j = i-crossValidationSize; j < i; ++j) {
									double predict = matchingAlgorithm2.predict(j);
									if ((predict - previousPredictTraining)*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
										directionCost++;
									}
									previousPredictTraining = predict;
									meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());	
								}
								
								if (directionCost < minDirectionCost) {
									minDirectionCost = directionCost;
									intervalPriceDirection = iIntervalPrice;
									intervalVolumeDirection = iIntervalVolume;
									priceCoefficentDirection = iPriceCoefficent;
									noSampleDirection = iNoSample;
								}
								
								if (meanSquareCost < minMeanSquareCost) {
									minMeanSquareCost = meanSquareCost;
									intervalPriceMeanSquare = iIntervalPrice;
									intervalVolumeMeanSquare = iIntervalVolume;
									priceCoefficentMeanSquare = iPriceCoefficent;
									noSampleMeanSquare = iNoSample;
								}
						}
					}
				}
			}
			
			countDirection[intervalPriceDirection][intervalVolumeDirection][priceCoefficentDirection][noSampleDirection]++;
			countMeanSquare[intervalPriceMeanSquare][intervalVolumeMeanSquare][priceCoefficentMeanSquare][noSampleMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose() + "," + priceEntities.get(i).getVolume();
			String parameterOutput = "";
			
			//Direction
			{
				matchingAlgorithm2.setIntervalPrice(intervalPrices[intervalPriceDirection]);
				matchingAlgorithm2.setIntervalVolume(intervalVolumes[intervalVolumeDirection]);
				matchingAlgorithm2.setPriceCoefficent(priceCoefficents[priceCoefficentDirection]);
				matchingAlgorithm2.setVolumeCoefficent(1 - priceCoefficents[priceCoefficentDirection]);
				matchingAlgorithm2.setNoSample(noSamples[noSampleDirection]);
				
				double predict = matchingAlgorithm2.predict(i);
				output += "," + predict + "," + intervalPrices[intervalPriceDirection] +"," + intervalVolumes[intervalVolumeDirection] +"," + priceCoefficents[priceCoefficentDirection] +"," + noSamples[noSampleDirection];
				for (Double para : matchingAlgorithm2.getParameterList()) {
					parameterOutput += "," + para;
				}

				if ((predict - previousPredictDirection)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainDirectionCost++;
				}
				previousPredictDirection = predict;
				testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
			}
			
			//Mean Square
			{
				matchingAlgorithm2.setIntervalPrice(intervalPrices[intervalPriceMeanSquare]);
				matchingAlgorithm2.setIntervalVolume(intervalVolumes[intervalVolumeMeanSquare]);
				matchingAlgorithm2.setPriceCoefficent(priceCoefficents[priceCoefficentMeanSquare]);
				matchingAlgorithm2.setVolumeCoefficent(1 - priceCoefficents[priceCoefficentMeanSquare]);
				matchingAlgorithm2.setNoSample(noSamples[noSampleMeanSquare]);
				
				double predict = matchingAlgorithm2.predict(i);
				output += "," + predict + "," + intervalPrices[intervalPriceMeanSquare] +"," + intervalVolumes[intervalVolumeMeanSquare] +"," + priceCoefficents[priceCoefficentMeanSquare] +"," + noSamples[noSampleMeanSquare];
				for (Double para : matchingAlgorithm2.getParameterList()) {
					parameterOutput += "," + para;
				}
				
				if ((predict - previousPredictPrice)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainMeanSquareCost++;
				}
				previousPredictPrice = predict;
				testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
			}

			System.out.println(output + parameterOutput);
			bufferedWriterResult.write(output + parameterOutput);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[15];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[9] = 0;
		result[14] = 0;
		for (int i = 0; i < intervalPrices.length; ++i) {
			for (int ii = 0; ii < intervalVolumes.length; ++ii) {
				for (int j = 0; j < priceCoefficents.length; ++j) {
					for (int k = 0; k < noSamples.length; ++k) {
							if (result[9] < countDirection[i][ii][j][k]) {
								result[9] = countDirection[i][ii][j][k];
								result[5] = intervalPrices[i];
								result[6] = intervalVolumes[ii];
								result[7] = priceCoefficents[j];
								result[8] = noSamples[k];
							}
							if (result[14] < countMeanSquare[i][ii][j][k]) {
								result[14] = countMeanSquare[i][ii][j][k];
								result[10] = intervalPrices[i];
								result[11] = intervalVolumes[ii];
								result[12] = priceCoefficents[j];
								result[13] = noSamples[k];
							}
					}
				}
			}
		}
		
		return result;
	}	
	
	public static double[] testingMatching3(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize) throws IOException {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("matching3_result_Q" + (calendar.get(Calendar.MONTH)/3 + 1) + "Y" + calendar.get(Calendar.YEAR) + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(
				printWriterResult);
		bufferedWriterResult.write("Date,Real,PredictTrainDirection,IntervalDirection,PriceCoefficentDirection,MaxDistanceDirection,PredictTrainMeanSquare,IntervalMeanSquare,PriceCoefficentMeanSquare,MaxDistanceMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		MatchingAlgorithm3 matchingAlgorithm3 = new MatchingAlgorithm3();
		matchingAlgorithm3.setPriceEntities(priceEntities);
		matchingAlgorithm3.setReferences(references);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] intervals = {5, 10, 15, 20};
		double[] priceCoefficents = {0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1};
		double[] maxDistances = {0.5,1.0,1.5,2.0,2.5,3.0,3.5,4.0,4.5};
		int[][][] countDirection = new int[intervals.length][priceCoefficents.length][maxDistances.length];
		int[][][] countMeanSquare = new int[intervals.length][priceCoefficents.length][maxDistances.length];
		
		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int intervalDirection = 0, priceCoefficentDirection = 0, maxDistanceDirection = 0;
			int intervalMeanSquare = 0, priceCoefficentMeanSquare = 0, maxDistanceMeanSquare = 0;
			
			for (int iInterval = 0; iInterval < intervals.length; ++iInterval) {
				for (int iPriceCoefficent = 0; iPriceCoefficent < priceCoefficents.length; ++iPriceCoefficent) {
					for (int iMaxDistance = 0; iMaxDistance < maxDistances.length; ++iMaxDistance) {
						matchingAlgorithm3.setInterval(intervals[iInterval]);
						matchingAlgorithm3.setPriceCoefficent(priceCoefficents[iPriceCoefficent]);
						matchingAlgorithm3.setVolumeCoefficent(1-priceCoefficents[iPriceCoefficent]);
						matchingAlgorithm3.setMaxAcceptableDistance(maxDistances[iMaxDistance]);
						
						double directionCost = 0, meanSquareCost = 0;
						
						for (int j = i-crossValidationSize; j < i; ++j) {
							double predict = matchingAlgorithm3.predict(j);
							if (predict == 0) {
								directionCost++;
								meanSquareCost += 0.1*priceEntities.get(j-1).getClose();
							} else {
								if ((predict - priceEntities.get(j-1).getClose())*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
									directionCost++;
								}
								meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());
							}
						}
						
						if (directionCost < minDirectionCost) {
							minDirectionCost = directionCost;
							intervalDirection = iInterval;
							priceCoefficentDirection = iPriceCoefficent;
							maxDistanceDirection = iMaxDistance;
						}
						
						if (meanSquareCost < minMeanSquareCost) {
							minMeanSquareCost = meanSquareCost;
							intervalMeanSquare = iInterval;
							priceCoefficentMeanSquare = iPriceCoefficent;
							maxDistanceMeanSquare = iMaxDistance;
						}
					}
				}
			}
			
			countDirection[intervalDirection][priceCoefficentDirection][maxDistanceDirection]++;
			countMeanSquare[intervalMeanSquare][priceCoefficentMeanSquare][maxDistanceMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose();
			
			//Direction
			{
				matchingAlgorithm3.setInterval(intervals[intervalDirection]);
				matchingAlgorithm3.setPriceCoefficent(priceCoefficents[priceCoefficentDirection]);
				matchingAlgorithm3.setVolumeCoefficent(1 - priceCoefficents[priceCoefficentDirection]);
				matchingAlgorithm3.setMaxAcceptableDistance(maxDistances[maxDistanceDirection]);
				
				double predict = matchingAlgorithm3.predict(i);
				output += "," + predict + "," + intervals[intervalDirection] + "," + priceCoefficents[priceCoefficentDirection] + "," + maxDistances[maxDistanceDirection];
				
				if (predict == 0) {
					testDirectionTrainDirectionCost++;
					testMeanSquareTrainDirectionCost += 0.1*priceEntities.get(i-1).getClose();					
				} else {
					if ((predict - priceEntities.get(i-1).getClose())*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
						testDirectionTrainDirectionCost++;
					}
					testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
				}
			}
			
			//Mean Square
			{
				matchingAlgorithm3.setInterval(intervals[intervalMeanSquare]);
				matchingAlgorithm3.setPriceCoefficent(priceCoefficents[priceCoefficentMeanSquare]);
				matchingAlgorithm3.setVolumeCoefficent(1 - priceCoefficents[priceCoefficentMeanSquare]);
				matchingAlgorithm3.setMaxAcceptableDistance(maxDistances[maxDistanceMeanSquare]);
				
				double predict = matchingAlgorithm3.predict(i);
				output += "," + predict + "," + intervals[intervalMeanSquare] + "," + priceCoefficents[priceCoefficentMeanSquare] + "," + maxDistances[maxDistanceMeanSquare];
				if (predict == 0 ) {
					testDirectionTrainMeanSquareCost++;
					testMeanSquareTrainMeanSquareCost += 0.1*priceEntities.get(i-1).getClose();					
				} else {
					if ((predict - priceEntities.get(i-1).getClose())*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
						testDirectionTrainMeanSquareCost++;
					}
					testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
				}
			}

			System.out.println(output);
			bufferedWriterResult.write(output);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[13];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[8] = 0;
		result[12] = 0;
		for (int i = 0; i < intervals.length; ++i) {
			for (int j = 0; j < priceCoefficents.length; ++j) {
				for (int k = 0; k < maxDistances.length; ++k) {
					if (result[8] < countDirection[i][j][k]) {
						result[8] = countDirection[i][j][k];
						result[5] = intervals[i];
						result[6] = priceCoefficents[j];
						result[7] = maxDistances[k];
					}
					if (result[12] < countMeanSquare[i][j][k]) {
						result[12] = countMeanSquare[i][j][k];
						result[9] = intervals[i];
						result[10] = priceCoefficents[j];
						result[11] = maxDistances[k];						
					}
				}
			}
		}
		
		return result;
	}

	public static double[] testingMatching4(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize) throws IOException {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("matching4_result_Q" + (calendar.get(Calendar.MONTH)/3 + 1) + "Y" + calendar.get(Calendar.YEAR) + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(
				printWriterResult);
		bufferedWriterResult.write("Date,Real,PredictTrainDirection,IntervalPriceDirection,IntervalVolumeDirection,PriceCoefficentDirection,MaxPriceDistanceDirection,MaxVolumeDistanceDirection,PredictTrainMeanSquare,IntervalPriceMeanSquare,IntervalVolumeMeanSquare,PriceCoefficentMeanSquare,maxPriceDistanceMeanSquare,maxVolumeDistanceMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		MatchingAlgorithm4 matchingAlgorithm4 = new MatchingAlgorithm4();
		matchingAlgorithm4.setPriceEntities(priceEntities);
		matchingAlgorithm4.setReferences(references);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] intervalPrices = {5, 10, 15, 20};
		int[] intervalVolumes = {5, 10, 15, 20};
		double[] priceCoefficents = {0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1};
		double[] maxPriceDistances = {0.01,0.02,0.04,0.08,0.16,0.32,0.64};
		double[] maxVolumeDistances = {0.5, 1, 2, 4, 8, 16, 32};
		int[][][][][] countDirection = new int[intervalPrices.length][intervalVolumes.length][priceCoefficents.length][maxPriceDistances.length][maxVolumeDistances.length];
		int[][][][][] countMeanSquare = new int[intervalPrices.length][intervalVolumes.length][priceCoefficents.length][maxPriceDistances.length][maxVolumeDistances.length];
		
		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int intervalPriceDirection = 0, intervalVolumeDirection = 0, priceCoefficentDirection = 0, maxPriceDistanceDirection = 0, maxVolumeDistanceDirection = 0;
			int intervalPriceMeanSquare = 0, intervalVolumeMeanSquare = 0, priceCoefficentMeanSquare = 0, maxPriceDistanceMeanSquare = 0, maxVolumeDistanceMeanSquare = 0;
			
			for (int iIntervalPrice = 0; iIntervalPrice < intervalPrices.length; ++iIntervalPrice) {
				for (int iIntervalVolume = 0; iIntervalVolume < intervalVolumes.length; ++iIntervalVolume) {
					for (int iPriceCoefficent = 0; iPriceCoefficent < priceCoefficents.length; ++iPriceCoefficent) {
						for (int iMaxPriceDistance = 0; iMaxPriceDistance < maxPriceDistances.length; ++iMaxPriceDistance) {
							for (int iMaxVolumeDistance = 0; iMaxVolumeDistance < maxVolumeDistances.length; ++iMaxVolumeDistance) {
								matchingAlgorithm4.setIntervalPrice(intervalPrices[iIntervalPrice]);
								matchingAlgorithm4.setIntervalVolume(intervalVolumes[iIntervalVolume]);
								matchingAlgorithm4.setPriceCoefficent(priceCoefficents[iPriceCoefficent]);
								matchingAlgorithm4.setVolumeCoefficent(1-priceCoefficents[iPriceCoefficent]);
								matchingAlgorithm4.setMaxPriceDistance(maxPriceDistances[iMaxPriceDistance]);
								matchingAlgorithm4.setMaxVolumeDistance(maxVolumeDistances[iMaxVolumeDistance]);
								
								double directionCost = 0, meanSquareCost = 0;
								
								for (int j = i-crossValidationSize; j < i; ++j) {
									double predict = matchingAlgorithm4.predict(j);
									
									if (predict == 0) {
										directionCost++;
										meanSquareCost += 0.1*priceEntities.get(j-1).getClose();
									} else {
										if ((predict - priceEntities.get(j-1).getClose())*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
											directionCost++;
										}
										meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());	
									}								
								}
								
								if (directionCost < minDirectionCost) {
									minDirectionCost = directionCost;
									intervalPriceDirection = iIntervalPrice;
									intervalVolumeDirection = iIntervalVolume;
									priceCoefficentDirection = iPriceCoefficent;
									maxPriceDistanceDirection = iMaxPriceDistance;
									maxVolumeDistanceDirection = iMaxVolumeDistance;
								}
								
								if (meanSquareCost < minMeanSquareCost) {
									minMeanSquareCost = meanSquareCost;
									intervalPriceMeanSquare = iIntervalPrice;
									intervalVolumeMeanSquare = iIntervalVolume;
									priceCoefficentMeanSquare = iPriceCoefficent;
									maxPriceDistanceMeanSquare = iMaxPriceDistance;
									maxVolumeDistanceMeanSquare = iMaxVolumeDistance;
								}
							}
						}
					}
				}
			}
			
			countDirection[intervalPriceDirection][intervalVolumeDirection][priceCoefficentDirection][maxPriceDistanceDirection][maxVolumeDistanceDirection]++;
			countMeanSquare[intervalPriceMeanSquare][intervalVolumeMeanSquare][priceCoefficentMeanSquare][maxPriceDistanceMeanSquare][maxVolumeDistanceMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose();
			
			//Direction
			{
				matchingAlgorithm4.setIntervalPrice(intervalPrices[intervalPriceDirection]);
				matchingAlgorithm4.setIntervalVolume(intervalVolumes[intervalVolumeDirection]);
				matchingAlgorithm4.setPriceCoefficent(priceCoefficents[priceCoefficentDirection]);
				matchingAlgorithm4.setVolumeCoefficent(1 - priceCoefficents[priceCoefficentDirection]);
				matchingAlgorithm4.setMaxPriceDistance(maxPriceDistances[maxPriceDistanceDirection]);
				matchingAlgorithm4.setMaxVolumeDistance(maxVolumeDistances[maxVolumeDistanceDirection]);
				
				double predict = matchingAlgorithm4.predict(i);
				output += "," + predict + "," + intervalPrices[intervalPriceDirection] +"," + intervalVolumes[intervalVolumeDirection] +"," + priceCoefficents[priceCoefficentDirection] +"," + maxPriceDistances[maxPriceDistanceDirection] + "," + maxVolumeDistances[maxVolumeDistanceDirection];
				
				if (predict == 0) {
					testDirectionTrainDirectionCost++;
					testMeanSquareTrainDirectionCost += 0.1*priceEntities.get(i-1).getClose();
				} else {				
					if ((predict - priceEntities.get(i-1).getClose())*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
						testDirectionTrainDirectionCost++;
					}
					testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
				}
			}
			
			//Mean Square
			{
				matchingAlgorithm4.setIntervalPrice(intervalPrices[intervalPriceMeanSquare]);
				matchingAlgorithm4.setIntervalVolume(intervalVolumes[intervalVolumeMeanSquare]);
				matchingAlgorithm4.setPriceCoefficent(priceCoefficents[priceCoefficentMeanSquare]);
				matchingAlgorithm4.setVolumeCoefficent(1 - priceCoefficents[priceCoefficentMeanSquare]);
				matchingAlgorithm4.setMaxPriceDistance(maxPriceDistances[maxPriceDistanceMeanSquare]);
				matchingAlgorithm4.setMaxVolumeDistance(maxVolumeDistances[maxVolumeDistanceMeanSquare]);
				
				double predict = matchingAlgorithm4.predict(i);
				output += "," + predict + "," + intervalPrices[intervalPriceMeanSquare] +"," + intervalVolumes[intervalVolumeMeanSquare] +"," + priceCoefficents[priceCoefficentMeanSquare] +"," + maxPriceDistances[maxPriceDistanceMeanSquare] + "," + maxVolumeDistances[maxVolumeDistanceMeanSquare];
				
				if (predict == 0) {
					testDirectionTrainMeanSquareCost++;
					testMeanSquareTrainMeanSquareCost += 0.1*priceEntities.get(i-1).getClose();
				} else {
					if ((predict - priceEntities.get(i-1).getClose())*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
						testDirectionTrainMeanSquareCost++;
					}
					testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
				}
			}

			System.out.println(output);
			bufferedWriterResult.write(output);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[17];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[10] = 0;
		result[16] = 0;
		for (int i = 0; i < intervalPrices.length; ++i) {
			for (int ii = 0; ii < intervalVolumes.length; ++ii) {
				for (int j = 0; j < priceCoefficents.length; ++j) {
					for (int k = 0; k < maxPriceDistances.length; ++k) {
						for (int l = 0; l < maxVolumeDistances.length; ++l) {
							if (result[10] < countDirection[i][ii][j][k][l]) {
								result[10] = countDirection[i][ii][j][k][l];
								result[5] = intervalPrices[i];
								result[6] = intervalVolumes[ii];
								result[7] = priceCoefficents[j];
								result[8] = maxPriceDistances[k];
								result[9] = maxVolumeDistances[l];
							}
							if (result[16] < countMeanSquare[i][ii][j][k][l]) {
								result[16] = countMeanSquare[i][ii][j][k][l];
								result[11] = intervalPrices[i];
								result[12] = intervalVolumes[ii];
								result[13] = priceCoefficents[j];
								result[14] = maxPriceDistances[k];
								result[15] = maxVolumeDistances[l];
							}
						}
					}
				}
			}
		}
		
		return result;
	}	

	public static double[] testingAutoRegression(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize, AssetEntity asset) throws IOException {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("autoregression_result_Y" + calendar.get(Calendar.YEAR) + "Q" + (calendar.get(Calendar.MONTH)/3 + 1) + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(
				printWriterResult);
		bufferedWriterResult.write("Date,Real,PredictTrainDirection,NoTrainingDirection,ARPeriodDirection,PredictTrainMeanSquare,NoTrainingMeanSquare,ARPeriodMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		AutoRegression autoRegression = new AutoRegression();
		autoRegression.setConfidenceLevel(0.9);
		autoRegression.setFutureInterval(1);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] noTrainingSamples = {5, 10, 30, 60, 90};
		int[] arPeriods = {2, 3, 5, 10, 15};
		int[][] countDirection = new int[noTrainingSamples.length][arPeriods.length];
		int[][] countMeanSquare = new int[noTrainingSamples.length][arPeriods.length];
		double previousPredictDirection = priceEntities.get(m-1).getClose();
		double previousPredictPrice = priceEntities.get(m-1).getClose();
		
		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int noTrainingSampleDirection = 0, arPeriodDirection = 0;
			int noTrainingSampleMeanSquare = 0, arPeriodMeanSquare = 0;
			
			for (int iNoTrainingSample = 0; iNoTrainingSample < noTrainingSamples.length; ++iNoTrainingSample) {
				for (int iArPeriod = 0; iArPeriod < arPeriods.length; ++iArPeriod) {
					if (arPeriods[iArPeriod] >= noTrainingSamples[iNoTrainingSample]-arPeriods[iArPeriod]) {
						continue;
					}
					autoRegression.setAR_period(arPeriods[iArPeriod]);
					
					double directionCost = 0, meanSquareCost = 0, previousPredictTraining = priceEntities.get(i-crossValidationSize - 1).getClose();;;
						
					for (int j = i-crossValidationSize; j < i; ++j) {
						TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
						ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();
	
						for (int k = j - noTrainingSamples[iNoTrainingSample]; k < j; k++) {
							training.add(priceEntities.get(k));
						}
						
						map.put(asset, training);
						autoRegression.setPriceEntityList(map);

						double predict = 0;
						
						try {
							predict = autoRegression.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
							directionCost++;
							meanSquareCost += 0.1*priceEntities.get(j-1).getClose();
							continue;
						}
						
						if ((predict - previousPredictTraining)*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
							directionCost++;
						}
						previousPredictTraining = predict;
						meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());
					}
						
					if (directionCost < minDirectionCost) {
						minDirectionCost = directionCost;
						noTrainingSampleDirection = iNoTrainingSample;
						arPeriodDirection = iArPeriod;
					}
					
					if (meanSquareCost < minMeanSquareCost) {
						minMeanSquareCost = meanSquareCost;
						noTrainingSampleMeanSquare = iNoTrainingSample;
						arPeriodMeanSquare = iArPeriod;
					}
				}
			}
			
			countDirection[noTrainingSampleDirection][arPeriodDirection]++;
			countMeanSquare[noTrainingSampleMeanSquare][arPeriodMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose();
			String parameterOutput = "";
			
			//Direction
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleDirection]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				autoRegression.setAR_period(arPeriods[arPeriodDirection]);
				autoRegression.setPriceEntityList(map);
				
				double predict = 0;
				
				try {
					predict = autoRegression.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleDirection] + "," + arPeriods[arPeriodDirection];
				
				for (Double para : autoRegression.getParameterList()) {
					parameterOutput += "," + para;
				}
				
				
				if (predict == 0) {
					testDirectionTrainDirectionCost++;
					testMeanSquareTrainDirectionCost += 0.1*priceEntities.get(i-1).getClose();
				} else {
					if ((predict - previousPredictDirection)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
						testDirectionTrainDirectionCost++;
					}
					previousPredictDirection = predict;
					testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
				}
			}
			
			//Mean Square
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleMeanSquare]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				autoRegression.setAR_period(arPeriods[arPeriodMeanSquare]);
				autoRegression.setPriceEntityList(map);
				
				double predict = 0;
				
				try {
					predict = autoRegression.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleMeanSquare] + "," + arPeriods[arPeriodMeanSquare];
				for (Double para : autoRegression.getParameterList()) {
					parameterOutput += "," + para;
				}
				
				if (predict == 0) {
					testDirectionTrainMeanSquareCost++;
					testMeanSquareTrainMeanSquareCost += 0.1*priceEntities.get(i-1).getClose();
				} else {
					if ((predict - previousPredictPrice)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
						testDirectionTrainMeanSquareCost++;
					}
					previousPredictPrice = predict;
					testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
				}
			}

			System.out.println(output + parameterOutput);
			bufferedWriterResult.write(output + parameterOutput);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[11];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[7] = 0;
		result[10] = 0;
		for (int i = 0; i < noTrainingSamples.length; ++i) {
			for (int j = 0; j < arPeriods.length; ++j) {
					if (result[7] < countDirection[i][j]) {
						result[7] = countDirection[i][j];
						result[5] = noTrainingSamples[i];
						result[6] = arPeriods[j];
					}
					if (result[10] < countMeanSquare[i][j]) {
						result[10] = countMeanSquare[i][j];
						result[8] = noTrainingSamples[i];
						result[9] = arPeriods[j];						
					}
			}
		}
		
		return result;
	}
	
	public static double[] testingARMA(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize, AssetEntity asset) throws IOException {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("ARMA_result_Y" + calendar.get(Calendar.YEAR) + "Q" + (calendar.get(Calendar.MONTH)/3 + 1) + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(
				printWriterResult);
		bufferedWriterResult.write("Date,Real,PredictTrainDirection,NoTrainingDirection,ARPeriodDirection,MA_PeriodsDirection,PredictTrainMeanSquare,NoTrainingMeanSquare,ARPeriodMeanSquare,MA_PeriodsMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		AutoRegressionMA autoRegressionMA = new AutoRegressionMA();
		autoRegressionMA.setConfidenceLevel(0.9);
		autoRegressionMA.setFutureInterval(1);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] noTrainingSamples = {5, 10, 30, 60, 90};
		int[] arPeriods = {2, 3, 5, 10, 15};
		int[] maPeriods = {1, 2, 3, 5, 10};
		int[][][] countDirection = new int[noTrainingSamples.length][arPeriods.length][maPeriods.length];
		int[][][] countMeanSquare = new int[noTrainingSamples.length][arPeriods.length][maPeriods.length];
		double previousPredictDirection = priceEntities.get(m-1).getClose();
		double previousPredictPrice = priceEntities.get(m-1).getClose();
		
		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int noTrainingSampleDirection = 0, arPeriodDirection = 0, maDirection = 0;
			int noTrainingSampleMeanSquare = 0, arPeriodMeanSquare = 0, maMeanSquare = 0;

			
			for (int iNoTrainingSample = 0; iNoTrainingSample < noTrainingSamples.length; ++iNoTrainingSample) {
				for (int iArPeriod = 0; iArPeriod < arPeriods.length; ++iArPeriod) {
					for (int iMAperiod = 0; iMAperiod < maPeriods.length; ++ iMAperiod) {
						if (arPeriods[iArPeriod] >= noTrainingSamples[iNoTrainingSample]-arPeriods[iArPeriod]) {
							continue;
						}
						autoRegressionMA.setAR_period(arPeriods[iArPeriod]);
						autoRegressionMA.setMA_period(maPeriods[iMAperiod]);
						
						double directionCost = 0, meanSquareCost = 0, previousPredictTraining = priceEntities.get(i-crossValidationSize - 1).getClose();;;
							
						for (int j = i-crossValidationSize; j < i; ++j) {
							TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
							ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();
		
							for (int k = j - noTrainingSamples[iNoTrainingSample]; k < j; k++) {
								training.add(priceEntities.get(k));
							}
							
							map.put(asset, training);
							autoRegressionMA.setPriceEntityList(map);
	
							double predict = 0;
							
							try {
								predict = autoRegressionMA.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
							} catch (Exception e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
								directionCost++;
								meanSquareCost += 0.1*priceEntities.get(j-1).getClose();
								continue;
							}
							
							if ((predict - previousPredictTraining)*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
								directionCost++;
							}
							previousPredictTraining = predict;
							meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());
						}
							
						if (directionCost < minDirectionCost) {
							minDirectionCost = directionCost;
							noTrainingSampleDirection = iNoTrainingSample;
							arPeriodDirection = iArPeriod;
							maDirection = iMAperiod;
						}
						
						if (meanSquareCost < minMeanSquareCost) {
							minMeanSquareCost = meanSquareCost;
							noTrainingSampleMeanSquare = iNoTrainingSample;
							arPeriodMeanSquare = iArPeriod;
							maMeanSquare = iMAperiod;
						}
					}
				}
			}
			
			countDirection[noTrainingSampleDirection][arPeriodDirection][maDirection]++;
			countMeanSquare[noTrainingSampleMeanSquare][arPeriodMeanSquare][maMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose();
			String parameterOutput = "";
			
			//Direction
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleDirection]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				autoRegressionMA.setAR_period(arPeriods[arPeriodDirection]);
				autoRegressionMA.setMA_period(maPeriods[maDirection]);
				autoRegressionMA.setPriceEntityList(map);
				
				double predict = 0;
				
				try {
					predict = autoRegressionMA.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleDirection] + "," + arPeriods[arPeriodDirection]+ "," + maPeriods[maDirection];
				for (Double para : autoRegressionMA.getParameterList()) {
					parameterOutput += "," + para;
				}

				if (predict == 0) {
					testDirectionTrainDirectionCost++;
					testMeanSquareTrainDirectionCost += 0.1*priceEntities.get(i-1).getClose();
				} else {
					if ((predict - previousPredictDirection)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
						testDirectionTrainDirectionCost++;
					}
					previousPredictDirection = predict;
					testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
				}
			}
			
			//Mean Square
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleMeanSquare]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				autoRegressionMA.setAR_period(arPeriods[arPeriodMeanSquare]);
				autoRegressionMA.setMA_period(maPeriods[maMeanSquare]);
				autoRegressionMA.setPriceEntityList(map);
				
				double predict = 0;
				
				try {
					predict = autoRegressionMA.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleMeanSquare] + "," + arPeriods[arPeriodMeanSquare]+ "," + maPeriods[maMeanSquare];
				for (Double para : autoRegressionMA.getParameterList()) {
					parameterOutput += "," + para;
				}

				if (predict == 0) {
					testDirectionTrainMeanSquareCost++;
					testMeanSquareTrainMeanSquareCost += 0.1*priceEntities.get(i-1).getClose();
				} else {
					if ((predict - previousPredictPrice)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
						testDirectionTrainMeanSquareCost++;
					}
					previousPredictPrice = predict;
					testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
				}
			}

			System.out.println(output + parameterOutput);
			bufferedWriterResult.write(output + parameterOutput);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[13];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[8] = 0;
		result[12] = 0;
		for (int i = 0; i < noTrainingSamples.length; ++i) {
			for (int j = 0; j < arPeriods.length; ++j) {
				for (int k = 0; k < maPeriods.length; ++k) {
					if (result[8] < countDirection[i][j][k]) {
						result[8] = countDirection[i][j][k];
						result[5] = noTrainingSamples[i];
						result[6] = arPeriods[j];
						result[7] = maPeriods[k];
					}
					if (result[12] < countMeanSquare[i][j][k]) {
						result[12] = countMeanSquare[i][j][k];
						result[9] = noTrainingSamples[i];
						result[10] = arPeriods[j];
						result[11] = maPeriods[k];
					}
				}
			}
		}
		
		return result;
	}
	
	public static double[] testingARFE(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize, AssetEntity asset) throws IOException {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("arfe_result_Y" + calendar.get(Calendar.YEAR) + "Q" + (calendar.get(Calendar.MONTH)/3 + 1) + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(
				printWriterResult);
		bufferedWriterResult.write("Date,Real,PredictTrainDirection,NoTrainingDirection,ARPeriodDirection,PredictTrainMeanSquare,NoTrainingMeanSquare,ARPeriodMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		AutoRegressionFE autoRegressionFE = new AutoRegressionFE();
		autoRegressionFE.setConfidenceLevel(0.9);
		autoRegressionFE.setFutureInterval(1);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] noTrainingSamples = {5, 10, 30, 60, 90};
		int[] arPeriods = {2, 3, 5, 10, 15};
		int[][] countDirection = new int[noTrainingSamples.length][arPeriods.length];
		int[][] countMeanSquare = new int[noTrainingSamples.length][arPeriods.length];
		double previousPredictDirection = priceEntities.get(m-1).getClose();
		double previousPredictPrice = priceEntities.get(m-1).getClose();
		
		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int noTrainingSampleDirection = 0, arPeriodDirection = 0;
			int noTrainingSampleMeanSquare = 0, arPeriodMeanSquare = 0;
			
			for (int iNoTrainingSample = 0; iNoTrainingSample < noTrainingSamples.length; ++iNoTrainingSample) {
				for (int iArPeriod = 0; iArPeriod < arPeriods.length; ++iArPeriod) {
					if (arPeriods[iArPeriod] >= noTrainingSamples[iNoTrainingSample]-arPeriods[iArPeriod]) {
						continue;
					}
					autoRegressionFE.setAR_period(arPeriods[iArPeriod]);
					
					double directionCost = 0, meanSquareCost = 0, previousPredictTraining = priceEntities.get(i-crossValidationSize - 1).getClose();;;
						
					for (int j = i-crossValidationSize; j < i; ++j) {
						TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
						ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();
	
						for (int k = j - noTrainingSamples[iNoTrainingSample]; k < j; k++) {
							training.add(priceEntities.get(k));
						}
						
						map.put(asset, training);
						autoRegressionFE.setPriceEntityList(map);

						double predict = 0;
						
						try {
							predict = autoRegressionFE.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
							directionCost++;
							meanSquareCost += 0.1*priceEntities.get(j-1).getClose();
							continue;
						}
						
						if ((predict - previousPredictTraining)*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
							directionCost++;
						}
						previousPredictTraining = predict;
						meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());
					}
						
					if (directionCost < minDirectionCost) {
						minDirectionCost = directionCost;
						noTrainingSampleDirection = iNoTrainingSample;
						arPeriodDirection = iArPeriod;
					}
					
					if (meanSquareCost < minMeanSquareCost) {
						minMeanSquareCost = meanSquareCost;
						noTrainingSampleMeanSquare = iNoTrainingSample;
						arPeriodMeanSquare = iArPeriod;
					}
				}
			}
			
			countDirection[noTrainingSampleDirection][arPeriodDirection]++;
			countMeanSquare[noTrainingSampleMeanSquare][arPeriodMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose();
			String parameterOutput = "";
			
			//Direction
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleDirection]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				autoRegressionFE.setAR_period(arPeriods[arPeriodDirection]);
				autoRegressionFE.setPriceEntityList(map);
				
				double predict = 0;
				
				try {
					predict = autoRegressionFE.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleDirection] + "," + arPeriods[arPeriodDirection];
				for (Double para : autoRegressionFE.getParameterList()) {
					parameterOutput += "," + para;
				}

				if (predict == 0) {
					testDirectionTrainDirectionCost++;
					testMeanSquareTrainDirectionCost += 0.1*priceEntities.get(i-1).getClose();
				} else {
					if ((predict - previousPredictDirection)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
						testDirectionTrainDirectionCost++;
					}
					previousPredictDirection = predict;
					testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
				}
			}
			
			//Mean Square
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleMeanSquare]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				autoRegressionFE.setAR_period(arPeriods[arPeriodMeanSquare]);
				autoRegressionFE.setPriceEntityList(map);
				
				double predict = 0;
				
				try {
					predict = autoRegressionFE.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleMeanSquare] + "," + arPeriods[arPeriodMeanSquare];
				for (Double para : autoRegressionFE.getParameterList()) {
					parameterOutput += "," + para;
				}

				if (predict == 0) {
					testDirectionTrainMeanSquareCost++;
					testMeanSquareTrainMeanSquareCost += 0.1*priceEntities.get(i-1).getClose();
				} else {
					if ((predict - previousPredictPrice)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
						testDirectionTrainMeanSquareCost++;
					}
					previousPredictPrice = predict;
					testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
				}
			}

			System.out.println(output + parameterOutput);
			bufferedWriterResult.write(output + parameterOutput);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[11];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[7] = 0;
		result[10] = 0;
		for (int i = 0; i < noTrainingSamples.length; ++i) {
			for (int j = 0; j < arPeriods.length; ++j) {
					if (result[7] < countDirection[i][j]) {
						result[7] = countDirection[i][j];
						result[5] = noTrainingSamples[i];
						result[6] = arPeriods[j];
					}
					if (result[10] < countMeanSquare[i][j]) {
						result[10] = countMeanSquare[i][j];
						result[8] = noTrainingSamples[i];
						result[9] = arPeriods[j];						
					}
			}
		}
		
		return result;
	}
	
	public static double[] testingBarycentric(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize, AssetEntity asset) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("barycentric_result_Y" + calendar.get(Calendar.YEAR) + "Q" + (calendar.get(Calendar.MONTH)/3 + 1) + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(
				printWriterResult);
		bufferedWriterResult.write("Date,Real,PredictTrainDirection,NoTrainingDirection,OrderDirection,PredictTrainMeanSquare,NoTrainingMeanSquare,OrderMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		BarycentricRationalExtrapolation barycentric = new BarycentricRationalExtrapolation();
		barycentric.setFutureInterval(1);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] noTrainingSamples = {2, 3, 5, 10, 15};
		int[] orders = {0, 1, 2, 3};
		int[][] countDirection = new int[5][4];
		int[][] countMeanSquare = new int[5][4];
		double previousPredictDirection = priceEntities.get(m-1).getClose();
		double previousPredictPrice = priceEntities.get(m-1).getClose();

		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int noTrainingSampleDirection = 0, orderDirection = 0;
			int noTrainingSampleMeanSquare = 0, orderMeanSquare = 0;
			
			for (int iNoTrainingSample = 0; iNoTrainingSample < noTrainingSamples.length; ++iNoTrainingSample) {
				for (int iOrder = 0; iOrder < orders.length; ++iOrder) {
					if (orders[iOrder] >= noTrainingSamples[iNoTrainingSample]) {
						continue;
					}
					barycentric.setOrderD(orders[iOrder]);
					
					double directionCost = 0, meanSquareCost = 0, previousPredictTraining = priceEntities.get(i-crossValidationSize - 1).getClose();;
						
					for (int j = i-crossValidationSize; j < i; ++j) {
						TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
						ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();
	
						for (int k = j - noTrainingSamples[iNoTrainingSample]; k < j; k++) {
							training.add(priceEntities.get(k));
						}
						
						map.put(asset, training);
						barycentric.setPriceEntityList(map);

						double predict = barycentric.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
						if ((predict - previousPredictTraining)*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
							directionCost++;
						}
						previousPredictTraining = predict;
						meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());
					}
						
						if (directionCost < minDirectionCost) {
							minDirectionCost = directionCost;
							noTrainingSampleDirection = iNoTrainingSample;
							orderDirection = iOrder;
						}
						
						if (meanSquareCost < minMeanSquareCost) {
							minMeanSquareCost = meanSquareCost;
							noTrainingSampleMeanSquare = iNoTrainingSample;
							orderMeanSquare = iOrder;
						}
				}
			}
			
			countDirection[noTrainingSampleDirection][orderDirection]++;
			countMeanSquare[noTrainingSampleMeanSquare][orderMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose();

			//Direction
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleDirection]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				barycentric.setOrderD(orders[orderDirection]);
				barycentric.setPriceEntityList(map);
				
				double predict = barycentric.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleDirection] + "," + orders[orderDirection];
				if ((predict - previousPredictDirection)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainDirectionCost++;
				}
				previousPredictDirection = predict;
				testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
			}
			
			//Mean Square
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleMeanSquare]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				barycentric.setOrderD(orders[orderMeanSquare]);
				barycentric.setPriceEntityList(map);
				
				double predict = barycentric.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleMeanSquare] + "," + orders[orderMeanSquare];
				if ((predict - previousPredictPrice)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainMeanSquareCost++;
				}
				previousPredictPrice = predict;
				testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
			}

			System.out.println(output);
			bufferedWriterResult.write(output);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[11];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[7] = 0;
		result[10] = 0;
		for (int i = 0; i < noTrainingSamples.length; ++i) {
			for (int j = 0; j < orders.length; ++j) {
					if (result[7] < countDirection[i][j]) {
						result[7] = countDirection[i][j];
						result[5] = noTrainingSamples[i];
						result[6] = orders[j];
					}
					if (result[10] < countMeanSquare[i][j]) {
						result[10] = countMeanSquare[i][j];
						result[8] = noTrainingSamples[i];
						result[9] = orders[j];						
					}
			}
		}
		
		return result;

	}
	
	public static double[] testingBaryMA(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize, AssetEntity asset) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("baryMA_result_Y" + calendar.get(Calendar.YEAR) + "Q" + (calendar.get(Calendar.MONTH)/3 + 1) + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(
				printWriterResult);
		bufferedWriterResult.write("Date,Real,PredictTrainDirection,NoTrainingDirection,OrderDirection,MA_PeriodsDirection,PredictTrainMeanSquare,NoTrainingMeanSquare,OrderMeanSquare,MA_PeriodsMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		BarycentricRationalMA barycentricMA = new BarycentricRationalMA();
		barycentricMA.setFutureInterval(1);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] noTrainingSamples = {2, 3, 5, 10, 15};
		int[] orders = {0, 1, 2, 3};
		int[] maPeriods = {1, 2, 3, 5, 10};
		int[][][] countDirection = new int[5][4][5];
		int[][][] countMeanSquare = new int[5][4][5];
		double previousPredictDirection = priceEntities.get(m-1).getClose();
		double previousPredictPrice = priceEntities.get(m-1).getClose();

		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int noTrainingSampleDirection = 0, orderDirection = 0, maDirection = 0;
			int noTrainingSampleMeanSquare = 0, orderMeanSquare = 0, maMeanSquare = 0;
			
			for (int iNoTrainingSample = 0; iNoTrainingSample < noTrainingSamples.length; ++iNoTrainingSample) {
				for (int iOrder = 0; iOrder < orders.length; ++iOrder) {
					for (int iMAperiod = 0; iMAperiod < maPeriods.length; ++ iMAperiod) {
						if (orders[iOrder] >= noTrainingSamples[iNoTrainingSample]) {
							continue;
						}
						barycentricMA.setOrderD(orders[iOrder]);
						barycentricMA.setMaPeriod(maPeriods[iMAperiod]);
						
						double directionCost = 0, meanSquareCost = 0, previousPredictTraining = priceEntities.get(i-crossValidationSize - 1).getClose();;
							
						for (int j = i-crossValidationSize; j < i; ++j) {
							TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
							ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();
		
							for (int k = j - noTrainingSamples[iNoTrainingSample]; k < j; k++) {
								training.add(priceEntities.get(k));
							}
							
							map.put(asset, training);
							barycentricMA.setPriceEntityList(map);
	
							double predict = barycentricMA.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
							if ((predict - previousPredictTraining)*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
								directionCost++;
							}
							previousPredictTraining = predict;
							meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());
						}
							
						if (directionCost < minDirectionCost) {
							minDirectionCost = directionCost;
							noTrainingSampleDirection = iNoTrainingSample;
							orderDirection = iOrder;
							maDirection = iMAperiod;
						}
						
						if (meanSquareCost < minMeanSquareCost) {
							minMeanSquareCost = meanSquareCost;
							noTrainingSampleMeanSquare = iNoTrainingSample;
							orderMeanSquare = iOrder;
							maMeanSquare = iMAperiod;
						}
					}
				}
			}
			
			countDirection[noTrainingSampleDirection][orderDirection][maDirection]++;
			countMeanSquare[noTrainingSampleMeanSquare][orderMeanSquare][maMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose();

			//Direction
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleDirection]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				barycentricMA.setOrderD(orders[orderDirection]);
				barycentricMA.setMaPeriod(maPeriods[maDirection]);
				barycentricMA.setPriceEntityList(map);
				
				double predict = barycentricMA.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleDirection] + "," + orders[orderDirection] + "," + maPeriods[maDirection];
				if ((predict - previousPredictDirection)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainDirectionCost++;
				}
				previousPredictDirection = predict;
				testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
			}
			
			//Mean Square
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleMeanSquare]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				barycentricMA.setOrderD(orders[orderMeanSquare]);
				barycentricMA.setMaPeriod(maPeriods[maMeanSquare]);
				barycentricMA.setPriceEntityList(map);
				
				double predict = barycentricMA.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleMeanSquare] + "," + orders[orderMeanSquare] + "," + maPeriods[maMeanSquare];
				if ((predict - previousPredictPrice)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainMeanSquareCost++;
				}
				previousPredictPrice = predict;
				testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
			}

			System.out.println(output);
			bufferedWriterResult.write(output);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[13];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[8] = 0;
		result[12] = 0;
		for (int i = 0; i < noTrainingSamples.length; ++i) {
			for (int j = 0; j < orders.length; ++j) {
				for (int k = 0; k < maPeriods.length; ++k) {
						if (result[8] < countDirection[i][j][k]) {
							result[8] = countDirection[i][j][k];
							result[5] = noTrainingSamples[i];
							result[6] = orders[j];
							result[7] = maPeriods[k];
						}
						if (result[12] < countMeanSquare[i][j][k]) {
							result[12] = countMeanSquare[i][j][k];
							result[9] = noTrainingSamples[i];
							result[10] = orders[j];
							result[11] = maPeriods[k];
						}
				}
			}
		}
		
		return result;

	}
	
	public static double[] testingBaryFE(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize, AssetEntity asset) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("baryFE_result_Y" + calendar.get(Calendar.YEAR) + "Q" + (calendar.get(Calendar.MONTH)/3 + 1) + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(
				printWriterResult);
		bufferedWriterResult.write("Date,Real,PredictTrainDirection,NoTrainingDirection,OrderDirection,PredictTrainMeanSquare,NoTrainingMeanSquare,OrderMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		BarycentricRationalFE barycentricFE = new BarycentricRationalFE();
		barycentricFE.setFutureInterval(1);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] noTrainingSamples = {2, 3, 5, 10, 15};
		int[] orders = {0, 1, 2, 3};
		int[][] countDirection = new int[5][4];
		int[][] countMeanSquare = new int[5][4];
		double previousPredictDirection = priceEntities.get(m-1).getClose();
		double previousPredictPrice = priceEntities.get(m-1).getClose();

		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int noTrainingSampleDirection = 0, orderDirection = 0;
			int noTrainingSampleMeanSquare = 0, orderMeanSquare = 0;
			
			for (int iNoTrainingSample = 0; iNoTrainingSample < noTrainingSamples.length; ++iNoTrainingSample) {
				for (int iOrder = 0; iOrder < orders.length; ++iOrder) {
					if (orders[iOrder] >= noTrainingSamples[iNoTrainingSample]) {
						continue;
					}
					barycentricFE.setOrderD(orders[iOrder]);
					
					double directionCost = 0, meanSquareCost = 0, previousPredictTraining = priceEntities.get(i-crossValidationSize - 1).getClose();;
						
					for (int j = i-crossValidationSize; j < i; ++j) {
						TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
						ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();
	
						for (int k = j - noTrainingSamples[iNoTrainingSample]; k < j; k++) {
							training.add(priceEntities.get(k));
						}
						
						map.put(asset, training);
						barycentricFE.setPriceEntityList(map);

						double predict = barycentricFE.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
						if ((predict - previousPredictTraining)*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
							directionCost++;
						}
						previousPredictTraining = predict;
						meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());
					}
						
						if (directionCost < minDirectionCost) {
							minDirectionCost = directionCost;
							noTrainingSampleDirection = iNoTrainingSample;
							orderDirection = iOrder;
						}
						
						if (meanSquareCost < minMeanSquareCost) {
							minMeanSquareCost = meanSquareCost;
							noTrainingSampleMeanSquare = iNoTrainingSample;
							orderMeanSquare = iOrder;
						}
				}
			}
			
			countDirection[noTrainingSampleDirection][orderDirection]++;
			countMeanSquare[noTrainingSampleMeanSquare][orderMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose();

			//Direction
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleDirection]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				barycentricFE.setOrderD(orders[orderDirection]);
				barycentricFE.setPriceEntityList(map);
				
				double predict = barycentricFE.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleDirection] + "," + orders[orderDirection];
				if ((predict - previousPredictDirection)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainDirectionCost++;
				}
				previousPredictDirection = predict;
				testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
			}
			
			//Mean Square
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleMeanSquare]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				barycentricFE.setOrderD(orders[orderMeanSquare]);
				barycentricFE.setPriceEntityList(map);
				
				double predict = barycentricFE.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleMeanSquare] + "," + orders[orderMeanSquare];
				if ((predict - previousPredictPrice)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainMeanSquareCost++;
				}
				previousPredictPrice = predict;
				testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
			}

			System.out.println(output);
			bufferedWriterResult.write(output);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[11];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[7] = 0;
		result[10] = 0;
		for (int i = 0; i < 5; ++i) {
			for (int j = 0; j < 4; ++j) {
					if (result[7] < countDirection[i][j]) {
						result[7] = countDirection[i][j];
						result[5] = noTrainingSamples[i];
						result[6] = orders[j];
					}
					if (result[10] < countMeanSquare[i][j]) {
						result[10] = countMeanSquare[i][j];
						result[8] = noTrainingSamples[i];
						result[9] = orders[j];						
					}
			}
		}
		
		return result;

	}

	public static double[] testingLagrange(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize, AssetEntity asset) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("Lagrange_result_Y" + calendar.get(Calendar.YEAR) + "Q" + (calendar.get(Calendar.MONTH)/3 + 1)  + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(printWriterResult);
		bufferedWriterResult.write("Date,Real,PredictTrainDirection,NoTrainingDirection,PredictTrainMeanSquare,NoTrainingMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		LagrangeExtrapolation lagrange = new LagrangeExtrapolation();
		lagrange.setFutureInterval(1);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] noTrainingSamples = {2, 3, 5, 7, 9};
		int[] countDirection = new int[5];
		int[] countMeanSquare = new int[5];
		double previousPredictDirection = priceEntities.get(m-1).getClose();
		double previousPredictPrice = priceEntities.get(m-1).getClose();
		
		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int noTrainingSampleDirection = 0;
			int noTrainingSampleMeanSquare = 0;
			
			for (int iNoTrainingSample = 0; iNoTrainingSample < noTrainingSamples.length; ++iNoTrainingSample) {
					
				double directionCost = 0, meanSquareCost = 0, previousPredictTraining = priceEntities.get(i-crossValidationSize - 1).getClose();
					
				for (int j = i-crossValidationSize; j < i; ++j) {
					TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
					ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

					for (int k = j - noTrainingSamples[iNoTrainingSample]; k < j; k++) {
						training.add(priceEntities.get(k));
					}
					
					map.put(asset, training);
					lagrange.setPriceEntityList(map);

					double predict = lagrange.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
					if ((predict - previousPredictTraining)*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
						directionCost++;
					}
					meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());
					previousPredictTraining = predict;
				}
					
				if (directionCost < minDirectionCost) {
					minDirectionCost = directionCost;
					noTrainingSampleDirection = iNoTrainingSample;
				}
				
				if (meanSquareCost < minMeanSquareCost) {
					minMeanSquareCost = meanSquareCost;
					noTrainingSampleMeanSquare = iNoTrainingSample;
				}
			}
			
			countDirection[noTrainingSampleDirection]++;
			countMeanSquare[noTrainingSampleMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose();
			String parameterOutput = "";

			//Direction
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleDirection]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				lagrange.setPriceEntityList(map);
				
				double predict = lagrange.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleDirection];
				for (Double para : lagrange.getParameterList()) {
					parameterOutput += "," + para;
				}

				if ((predict - previousPredictDirection)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainDirectionCost++;
				}
				previousPredictDirection= predict;
				testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
			}
			
			//Mean Square
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleMeanSquare]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				lagrange.setPriceEntityList(map);
				
				double predict = lagrange.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleMeanSquare];
				for (Double para : lagrange.getParameterList()) {
					parameterOutput += "," + para;
				}

				if ((predict - previousPredictPrice)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainMeanSquareCost++;
				}
				previousPredictPrice = predict;
				testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
			}

			System.out.println(output + parameterOutput);
			bufferedWriterResult.write(output + parameterOutput);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[11];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[6] = 0;
		result[8] = 0;
		for (int i = 0; i < 5; ++i) {
			if (result[6] < countDirection[i]) {
				result[6] = countDirection[i];
				result[5] = noTrainingSamples[i];
			}
			if (result[8] < countMeanSquare[i]) {
				result[8] = countMeanSquare[i];
				result[7] = noTrainingSamples[i];
			}
		}
		
		return result;

	}
	
	public static double[] testingLagrangeMA(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize, AssetEntity asset) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("LagrangeMA_result_Y" + calendar.get(Calendar.YEAR) + "Q" + (calendar.get(Calendar.MONTH)/3 + 1)  + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(printWriterResult);
		bufferedWriterResult.write("Date,Real,PredictTrainDirection,NoTrainingDirection,MA_PeriodDirection,PredictTrainPrice,NoTrainingPrice,MA_PeriodPrice");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		LagrangeMA lagrangeMA = new LagrangeMA();
		lagrangeMA.setFutureInterval(1);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] noTrainingSamples = {2, 3, 5, 10, 15};
		int[] maPeriods = {1, 2, 3, 5, 10};
		int[][] countDirection = new int[5][5];
		int[][] countMeanSquare = new int[5][5];
		double previousPredictDirection = priceEntities.get(m-1).getClose();
		double previousPredictPrice = priceEntities.get(m-1).getClose();

		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int noTrainingSampleDirection = 0;
			int maPeriodDirection = 0;
			int noTrainingSamplePrice = 0;
			int maPeriodPrice = 0;
			
			for (int iNoTrainingSample = 0; iNoTrainingSample < noTrainingSamples.length; ++iNoTrainingSample) {
				for (int iMaPeriod = 0; iMaPeriod < maPeriods.length; ++iMaPeriod) {
					
					double directionCost = 0, meanSquareCost = 0, previousPredictTraining = priceEntities.get(i-crossValidationSize - 1).getClose();;
						
					for (int j = i-crossValidationSize; j < i; ++j) {
						TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
						ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();
	
						for (int k = j - noTrainingSamples[iNoTrainingSample]; k < j; k++) {
							training.add(priceEntities.get(k));
						}
						
						map.put(asset, training);
						lagrangeMA.setPriceEntityList(map);
						lagrangeMA.setMA_period(maPeriods[iMaPeriod]);
	
						double predict = lagrangeMA.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
						if ((predict - previousPredictTraining)*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
							directionCost++;
						}
						previousPredictTraining= predict;
						meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());
					}
						
					if (directionCost < minDirectionCost) {
						minDirectionCost = directionCost;
						noTrainingSampleDirection = iNoTrainingSample;
						maPeriodDirection = iMaPeriod;
					}
					
					if (meanSquareCost < minMeanSquareCost) {
						minMeanSquareCost = meanSquareCost;
						noTrainingSamplePrice = iNoTrainingSample;
						maPeriodPrice = iMaPeriod;
					}
				}
			}
			
			countDirection[noTrainingSampleDirection][maPeriodDirection]++;
			countMeanSquare[noTrainingSamplePrice][maPeriodPrice]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose();

			//Direction
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleDirection]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				lagrangeMA.setPriceEntityList(map);
				lagrangeMA.setMA_period(maPeriodDirection);
				
				double predict = lagrangeMA.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleDirection] + "," + maPeriods[maPeriodDirection];
				if ((predict - previousPredictDirection)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainDirectionCost++;
				}
				previousPredictDirection = predict;
				testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
			}
			
			//Mean Square
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSamplePrice]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				lagrangeMA.setPriceEntityList(map);
				lagrangeMA.setMA_period(maPeriodPrice);
				
				double predict = lagrangeMA.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				output += "," + predict + "," + noTrainingSamples[noTrainingSamplePrice]  + "," + maPeriods[maPeriodPrice];
				if ((predict - previousPredictPrice)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainMeanSquareCost++;
				}
				previousPredictPrice = predict;
				testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
			}

			System.out.println(output);
			bufferedWriterResult.write(output);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[11];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[7] = 0;
		result[10] = 0;
		for (int i = 0; i < 5; ++i) {
			for (int j = 0; j < 5; ++j) {
				if (result[7] < countDirection[i][j]) {
					result[7] = countDirection[i][j];
					result[5] = noTrainingSamples[i];
					result[6] = maPeriods[j];
				}
				if (result[10] < countMeanSquare[i][j]) {
					result[10] = countMeanSquare[i][j];
					result[8] = noTrainingSamples[i];
					result[9] = maPeriods[j];
				}
			}
		}
		
		return result;

	}
	
	public static double[] testingLagrangeFE(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities, int crossValidationSize, AssetEntity asset) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		File resultFile = new File("LagrangeFE_result_Y" + calendar.get(Calendar.YEAR) + "Q" + (calendar.get(Calendar.MONTH)/3 + 1)  + ".csv");
		FileWriter printWriterResult = new FileWriter(resultFile);
		BufferedWriter bufferedWriterResult = new BufferedWriter(printWriterResult);
		bufferedWriterResult.write("Date,Real,PredictTrainDirection,NoTrainingDirection,PredictTrainMeanSquare,NoTrainingMeanSquare");
		bufferedWriterResult.newLine();
		
		int[] indices = chooseRange(startDate, endDate, priceEntities);
		int m = indices[0];
		int n = indices[1];
		LagrangeFE lagrange = new LagrangeFE();
		lagrange.setFutureInterval(1);
		
		double testDirectionTrainDirectionCost = 0, testMeanSquareTrainDirectionCost = 0,
				testDirectionTrainMeanSquareCost = 0, testMeanSquareTrainMeanSquareCost = 0;
		
		int[] noTrainingSamples = {2, 3, 5, 7, 9};
		int[] countDirection = new int[5];
		int[] countMeanSquare = new int[5];
		double previousPredictDirection = priceEntities.get(m-1).getClose();
		double previousPredictPrice = priceEntities.get(m-1).getClose();
		
		for (int i = m; i < n; ++i) {			
			double minDirectionCost = Double.MAX_VALUE, minMeanSquareCost = Double.MAX_VALUE;
			int noTrainingSampleDirection = 0;
			int noTrainingSampleMeanSquare = 0;
			
			for (int iNoTrainingSample = 0; iNoTrainingSample < noTrainingSamples.length; ++iNoTrainingSample) {
					
				double directionCost = 0, meanSquareCost = 0, previousPredictTraining = priceEntities.get(i-crossValidationSize - 1).getClose();;
					
				for (int j = i-crossValidationSize; j < i; ++j) {
					TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
					ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

					for (int k = j - noTrainingSamples[iNoTrainingSample]; k < j; k++) {
						training.add(priceEntities.get(k));
					}
					
					map.put(asset, training);
					lagrange.setPriceEntityList(map);

					double predict = lagrange.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
					if ((predict - previousPredictTraining)*(priceEntities.get(j).getClose()-priceEntities.get(j-1).getClose()) < 0) {
						directionCost++;
					}
					previousPredictTraining = predict;
					meanSquareCost += Math.abs(predict - priceEntities.get(j).getClose());
				}
					
				if (directionCost < minDirectionCost) {
					minDirectionCost = directionCost;
					noTrainingSampleDirection = iNoTrainingSample;
				}
				
				if (meanSquareCost < minMeanSquareCost) {
					minMeanSquareCost = meanSquareCost;
					noTrainingSampleMeanSquare = iNoTrainingSample;
				}
			}
			
			countDirection[noTrainingSampleDirection]++;
			countMeanSquare[noTrainingSampleMeanSquare]++;
			String output = priceEntities.get(i).getDate() + "," + priceEntities.get(i).getClose();

			//Direction
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleDirection]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				lagrange.setPriceEntityList(map);
				
				double predict = lagrange.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleDirection];
				if ((predict - previousPredictDirection)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainDirectionCost++;
				}
				previousPredictDirection = predict;
				testMeanSquareTrainDirectionCost += Math.abs(predict - priceEntities.get(i).getClose());
			}
			
			//Mean Square
			{
				TreeMap<AssetEntity, ArrayList<PriceEntity>> map = new TreeMap<AssetEntity, ArrayList<PriceEntity>>();
				ArrayList<PriceEntity> training = new ArrayList<PriceEntity>();

				for (int k = i - noTrainingSamples[noTrainingSampleMeanSquare]; k < i; k++) {
					training.add(priceEntities.get(k));
				}
				
				map.put(asset, training);

				lagrange.setPriceEntityList(map);
				
				double predict = lagrange.runAlgorithm().getPredictionPriceList().firstEntry().getValue().get(1).getPrice();
				output += "," + predict + "," + noTrainingSamples[noTrainingSampleMeanSquare];
				if ((predict - previousPredictPrice)*(priceEntities.get(i).getClose()-priceEntities.get(i-1).getClose()) < 0) {
					testDirectionTrainMeanSquareCost++;
				}
				previousPredictPrice = predict;
				testMeanSquareTrainMeanSquareCost += Math.abs(predict - priceEntities.get(i).getClose());
			}

			System.out.println(output);
			bufferedWriterResult.write(output);
			bufferedWriterResult.newLine();
			bufferedWriterResult.flush();
		}
		
		bufferedWriterResult.close();
		
		double[] result = new double[11];
		
		result[0] = n - m;
		result[1] = testDirectionTrainDirectionCost/result[0];
		result[2] = testMeanSquareTrainDirectionCost/result[0];
		result[3] = testDirectionTrainMeanSquareCost/result[0];
		result[4] = testMeanSquareTrainMeanSquareCost/result[0];
		
		result[6] = 0;
		result[8] = 0;
		for (int i = 0; i < 5; ++i) {
			if (result[6] < countDirection[i]) {
				result[6] = countDirection[i];
				result[5] = noTrainingSamples[i];
			}
			if (result[8] < countMeanSquare[i]) {
				result[8] = countMeanSquare[i];
				result[7] = noTrainingSamples[i];
			}
		}
		
		return result;

	}

	public static int[] chooseRange(Date startDate, Date endDate, ArrayList<PriceEntity> priceEntities) {
		int[] result = new int[2];
		
		//choose range for test
		{
			for (int i = 0; i < priceEntities.size(); ++i) {
				if (priceEntities.get(i).getDate().compareTo(startDate) > 0) {
					result[0] = i;
					break;
				}
			}

			for (int i = 0; i < priceEntities.size(); ++i) {
				if (priceEntities.get(i).getDate().compareTo(endDate) > 0) {
					result[1] = i;
					break;
				}
			}
		}
		
		return result;
	}
}
